iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 6
0
自我挑戰組

JavaScript 30 挑戰日誌系列 第 6

Day 06:搜尋地區名稱

  • 分享至 

  • xImage
  •  

作品 Demo 連結: 傳送門

作品目標:輸入關鍵字會自動過濾出相關地區名稱,並且 hightlight 我們所輸入的文字
難易度:★★★☆☆

HTML

<form class="search-form">
    <input type="text" class="search" placeholder="City or State">
    <ul class="suggestions">
      <li>Filter for a city</li>
      <li>or a state</li>
    </ul>
</form>

會使用到的 CSS

.hl { background:#ffc600; }

初始 JavaScript

const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

//將 數字自動加上逗點的函數
function numberWithCommas(x){
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ', ');
}

【第一步:取得 JSON 資料】

在一開始的 START 檔案中,作者就給了我們 JSON 的連結
第一個步驟就是要將遠端的 JSON 檔案傳存為陣列物件到我們本地的變數中

const cities = [];

fetch(endpoint)
    .then(blob => blob.json())
    .then(data => cities.push(...data));

因為使用 原生JavaScript 的 AJAX 之後其實會很難維護,
所以在 ES6 時推出了 fetch() 這一個函數!

.then() 這裡是類似 callback 功能
第一個 .then() 是在下載完成後將檔案轉檔成物件
第二個 .then() 是將我們接收到的資料
一個一個的 push() 到 cities 這個陣列變數裡頭。

關於 ... 的部分我還不是很清楚,
目前還查不到,但這邊的作用是將元素不論幾層,
都將其 push() 到 cities 陣列中。

這樣我們的 cities 裡頭就有 1,000 筆美國地區資訊囉!

【第二步:過濾使用者輸入的文字】

function findMatches(wordToMatch, cities){
    return cities.filter(place => {
        const regex = new RegExp(wordToMatch, 'gi')
        return place.city.match(regex) || place.state.match(regex);
    });
}

創立一個名為 findMatches 的函數
第一個參數為 使用者輸入的文字
第二個參數為我們的資料陣列

我們針對 cities 內容元素一筆一筆去做過濾
使用到我們之前學過的陣列功能 .filter()

RegExp 平時可以只用它特殊的寫法去過濾即可,
只是我們在這裡要過濾的是個變數,
這時候就需要 new 一個 RegExp 出來
後頭的 'gi' 代表的兩個功能
1. 'g':整個 data 都查找,而不是只找到第一個之後就停止
2. 'i':代表不用區分大小寫

最後我們不論是資料裡的 city 屬性 或是 state 屬性,
只要有符合的,通通都回傳

RegExp 相關用法很複雜並不在此次討論範圍,
有興趣的可以上網爬文 =)

【第三步:將符合的資料顯示出來】

function displayMatches(){
    const matchArray = findMatches(this.value, cities);
    const html = matchArray.map(place => {
        const regex = new RegExp(this.value, 'gi');

        const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`);
        const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`);

        return `
            <li>
              <span class="name">${cityName}, ${stateName}</span>
              <span class="population">${numberWithCommas(place.population)}</span>
            </li>
        `;
    }).join('');

    suggestions.innerHTML = html;
}

matchArray 變數以陣列狀態存放第二步函數過濾後的資料

接著我們使用 .map() 遍歷陣列每個元素
再一次的使用到 RegExp
如果資料中如果有我們輸入的文字,
則將其過濾出來用 span.hl 包裹起來,
否則不用包

最後再放入 HTML 公版裡頭後回傳
最後 innerHTML 放入 .suggestion 區塊裡頭做顯示!

numberWithCommas(place.population) 這個函數是作者事先幫我們寫好
使用 RegExp 語法將數字自動加上逗點
這個比較進階,在此作者說可先略過

【第四步:綁定事件、呼叫已寫好的函數】

const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

searchInput.addEventListener('change', displayMatches);
searchInput.addEventListener('keyup', displayMatches);

這裡我就不多做解釋囉! (偷懶!!! X"P


小北心裡話:

這是我第一次參加鐵人競賽
最近個人有些私事壓力頗大...
發現鐵人賽要持續下去真的超級難 QAQ
有時候真的會跟自己說幹麻自己找罪受...

在此我要深深的向每位可以把文章寫得超棒
又可以每日穩定量產的鐵人們表達我的敬意!!

大家繼續加油!!!
也希望我的肝可以繼續努力地撐下去!!


上一篇
Day 05:使用 class 控制 flex
下一篇
Day 07:陣列習題 (2)
系列文
JavaScript 30 挑戰日誌8
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言